package com.platform.comm.common.batch;

import com.google.common.collect.Lists;
import com.platform.batch.base.exception.JobExecuteFailedException;
import com.platform.batch.base.exception.JobNeedSkippedException;
import com.platform.batch.base.exception.JobSkippedWithLimitException;
import com.platform.comm.common.batch.listener.ComExportJobListener;
import com.platform.comm.common.batch.listener.CustomItemWriterListener;
import com.platform.comm.common.batch.listener.CustomSkipListener;
import com.platform.comm.common.batch.listener.exportor.ComExportStepExecutionListener;
import com.platform.comm.common.batch.processor.ComExportDataTransformProcessor;
import com.platform.comm.common.batch.step.DataTranslateProcessor;
import com.platform.comm.common.batch.step.DataValidationProcessor;
import com.platform.comm.common.batch.writer.SysExpItemWriter;
import com.platform.comm.service.ICommBatchInfoBiz;
import com.platform.vo.ImportDto;
import org.springframework.batch.core.ItemWriteListener;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecutionListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.JobScope;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.database.JdbcPagingItemReader;
import org.springframework.batch.item.support.CompositeItemProcessor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.policy.NeverRetryPolicy;

import javax.annotation.Nullable;
import javax.sql.DataSource;
import java.util.List;
import java.util.Map;

/**
 * Description: 通用批量导出配置
 *
 * @author lch Created on 2020/1/8
 **/
@Configuration
public class ComBatchExportConfig {

    private final JobBuilderFactory jobBuilderFactory;
    private final StepBuilderFactory stepBuilderFactory;
    public final DataSource dataSource;
    private final ICommBatchInfoBiz dirBatchInfoBiz;

    public ComBatchExportConfig(JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory,
                                                        DataSource dataSource, ICommBatchInfoBiz dirBatchInfoBiz) {
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
        this.dataSource = dataSource;
        this.dirBatchInfoBiz = dirBatchInfoBiz;
    }

    @Bean
    public Job comExportJob() {
        return jobBuilderFactory.get("comExportJob")
                .incrementer(new RunIdIncrementer())
                .start(comExportStep())
                .listener(jobExecutionListener(null))
                .build();
    }

    @Bean
    public Step comExportStep() {
        return stepBuilderFactory.get("comExportStep")
                .listener(comDataCountStepExecutionListener(null))
                .<Map<String, Object>, ImportDto>chunk(1000)
                .reader(jdbcPagingItemReader(null, dataSource))
                .processor(compositeItemProcessor())
                .writer(comExportToExcelWriter(null)).listener(itemWriteListener())
                .faultTolerant().skipLimit(100).skip(JobSkippedWithLimitException.class)
                .skip(JobNeedSkippedException.class)
                .noSkip(JobExecuteFailedException.class)
                .retryPolicy(new NeverRetryPolicy())
                .listener(new CustomSkipListener())
                .build();
    }

    @Bean("comExportJobExecutionListener")
    @JobScope
    public JobExecutionListener jobExecutionListener(
            @Nullable
            @Value("#{jobExecutionContext['config']}") ComBatchExportContext config) {
        assert config != null;
        return new ComExportJobListener(config, dirBatchInfoBiz);
    }

    @Bean("comExportItemWriteListener")
    @StepScope
    public ItemWriteListener<ImportDto> itemWriteListener() {
        return new CustomItemWriterListener();
    }

    @Bean("comExportJdbcPagingItemReader")
    @StepScope
    public JdbcPagingItemReader<Map<String, Object>> jdbcPagingItemReader(
            @Nullable
            @Value("#{jobExecutionContext['config']}") ComBatchExportContext config, DataSource dataSource) {
        assert config != null;
        return config.buildJdbcPagingItemReader(config, dataSource);
    }

    @Bean("comExportDataValidationProcessor")
    @StepScope
    public ItemProcessor<Map<String, String>, Map> comDataValidationProcessor() {
        return new DataValidationProcessor();
    }

    @Bean("comExportDataTranslateProcessor")
    @StepScope
    public ItemProcessor<Map<String, String>, Map> comDataTranslateProcessor() {
        return new DataTranslateProcessor();
    }

    @Bean("comExportCompositeItemProcessor")
    @StepScope
    public ItemProcessor<Map<String, Object>, ImportDto> compositeItemProcessor() {
        CompositeItemProcessor<Map<String, Object>, ImportDto> compositeItemProcessor = new CompositeItemProcessor<>();
        List<ItemProcessor<Map<String, Object>, ImportDto>> list = Lists.newArrayList();
        list.add(comExportDataTransformProcessor(null));

        compositeItemProcessor.setDelegates(list);

        return compositeItemProcessor;
    }

    @Bean
    @StepScope
    public ItemProcessor<Map<String, Object>, ImportDto> comExportDataTransformProcessor(
            @Nullable
            @Value("#{jobExecutionContext['config']}")  ComBatchExportContext config) {
        assert config != null;
        return new ComExportDataTransformProcessor(config);
    }

    @Bean("comExportToExcelWriter")
    @StepScope
    public SysExpItemWriter comExportToExcelWriter(@Nullable
                                                    @Value("#{jobExecutionContext['config']}") ComBatchExportContext config) {
        assert config != null;
        return new SysExpItemWriter(config);
    }

    @Bean
    @StepScope
    public ComExportStepExecutionListener comDataCountStepExecutionListener(
                                          @Nullable
                                          @Value("#{jobExecutionContext['config']}") ComBatchExportContext config) {
        assert config != null;
        return new ComExportStepExecutionListener(config);
    }


}
